/**
 * 作者: Jason
 * 版本：0.1.0
 * git: https://gitee.com/JasonShow/time-rule.git
 */

function TimeRule() {
  // 设置默认值
  this.el = '' // 容器id
  this.recordData = [] // 有视频记录的时间段
  this.space = 30 // 时间间隔60分钟
  this.isShowToolBar = true // 是否显示放大缩小时间间隔的按钮
  this.themeColor = '#009688' // 进度条的背景色
}

TimeRule.timeId1 = null // 定时移动指针的定时器id
TimeRule.timeId2 = null // 定时更新当前时间的定时器id
TimeRule.current = 0 // 指针处在从左往右数第current个视频上, null表示指针不在任何一个视频上
TimeRule.dragSuccess = null // 拖拽结束后有视频记录则触发dragSuccess
TimeRule.dragError = null // 拖拽结束后无视频记录则触发dragSuccess
TimeRule.beforeInit = null // 初始化之前调用
TimeRule.afterInit = null // 初始化之后调用

// 时间轴个组成部分JQ的Dom 对象
TimeRule.container = null // 存放时间轴的容器
TimeRule.timeRule = null // 时间轴
TimeRule.point = null // 指针
TimeRule.mark = null // 刻度尺
TimeRule.prograss = null //  进度条
TimeRule.prograssItem = null // 进度条里的视频段集合
TimeRule.toolBar = null // 工具栏
TimeRule.toolBarItem = null // 工具栏每一项（3min 30min 60）
TimeRule.time = null // 指针里的展示时间

// 根据时间戳计算时间 YYYY-MM-DD hh:mm:ss
TimeRule.timestampToTime = function (timestamp) {
  var date = new Date(timestamp);//时间戳为10位需*1000，时间戳为13位的话不需乘1000
  var Y = date.getFullYear() + '-';
  var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
  var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ';
  var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
  var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
  var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
  return Y + M + D + h + m + s;
}

// 解决乘法精度丢失
TimeRule.mul = function(arg1, arg2) {
  var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
  try { m += s1.split(".")[1].length } catch (e) { }
  try { m += s2.split(".")[1].length } catch (e) { }
  return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
}
// 判断当前指针位置是否有视频
TimeRule.hasVideo = function (pointLeft) {
  var hasVideo = false // 当前是否有视频的标识
  $('.time-rule-prograss-item').each(function (i, item) {
    var startLeft = $(item).data('startleft')
    var endLeft = $(item).data('endleft')
    if (pointLeft <= endLeft && pointLeft >= startLeft) {
      hasVideo = true
      TimeRule.current = i
      return false
    }
  })
  return hasVideo
}
// 动态显示当前时间
TimeRule.updateTime = function () {
  var time = TimeRule.time.text()
  var hour = time.split(':')[0]
  var minute = time.split(':')[1]
  var second = time.split(':')[2]
  TimeRule.timeId2 = setInterval(function () {
    second = Number(second)
    minute = Number(minute)
    hour = Number(hour)
    second += 1
    if (second >= 60) {
      second = 0
      minute += 1
    }
    if (minute >= 60) {
      minute = 0
      hour += 1
    }
    if (hour >= 24) {
      hour = 0
    }
    // 补0
    if (String(minute).length === 1) minute = '0' + minute
    if (String(hour).length === 1) hour = '0' + hour
    if (String(second).length === 1) second = '0' + second
    TimeRule.time.text(hour + ':' + minute + ':' + second)
  }, 1000)
}

// 拖拽指针
TimeRule.dragPoint = function (that) {
  var space = that.space
  var PER = space / $('.time-text').outerWidth() // 1个像素对应PER分钟
  var flag = false //设置一个开关，初始值为false，表示关闭，根据flag限定事件的执行与否
  var x = 0 // 鼠标到point左侧的水平距离
  var container = TimeRule.container
  var point = TimeRule.point
  var pointOffsetLeft = point.offset().left
  var containerOffsetLeft = container.offset().left
  var timeRule = TimeRule.timeRule
  var timeRuleWidth = timeRule.width()
  var pointWidth = TimeRule.point.outerWidth()
  var left = 0  // point实时水平距离
  var text = '' // 指针展示的时间
  count = 60 * 24 / space // li元素个数
  point.on('mousedown', function (event) {
    event = event || window.event // 兼容ie
    event.stopPropagation();
    flag = true //阀门开启
    pointOffsetLeft = $(this).offset().left // point到可视区域的水平距离
    x = event.pageX - pointOffsetLeft
    text = TimeRule.time.text()
    $(this).css('transition', 'none')
    if (TimeRule.timeId1 !== null) clearInterval(TimeRule.timeId1)
    if (TimeRule.timeId2 !== null) clearInterval(TimeRule.timeId2)
  })
  $(document).on('mousemove', function (event) {
    if (flag) {
      event = event || window.event
      left = event.pageX - x - containerOffsetLeft - parseFloat(timeRule.css('left'))
      event.stopPropagation();
      // 限制拖拽范围，移动point
      if ((left >= 0 - (pointWidth / 2) && left <= timeRuleWidth - (pointWidth / 2))) {
        point.css({ left: Math.ceil(left) })
        // 时间轴宽度大于可视区域宽度，指针拖到可视区域边缘自动调整时间轴位置
        if (timeRuleWidth > container.width()) {
          if (parseFloat(timeRule.css('left')) + left < -1 * (pointWidth / 2) && parseFloat(timeRule.css('left')) < 0) {
            // 指针在可视区域左侧
            timeRule.css('left', parseFloat(timeRule.css('left')) + 20)
            if (parseFloat(timeRule.css('left')) > 0) {
              timeRule.css('left', 0)
            }
            point.css({ left: parseFloat(timeRule.css('left')) * -1 - (pointWidth / 2) })
          }
          if (parseFloat(timeRule.css('left')) + left > container.width() - (pointWidth / 2) && parseFloat(timeRule.css('left')) > -1 * (timeRuleWidth - container.width())) {
            // 指针在可视区域右侧
            timeRule.css('left', parseFloat(timeRule.css('left')) - 20)
            if (parseFloat(timeRule.css('left')) < -1 * (timeRuleWidth - container.width())) {
              timeRule.css('left', -1 * (timeRuleWidth - container.width()))
            }
            point.css({ left: (parseFloat(timeRule.css('left')) * -1 + container.width()) - (pointWidth / 2) })
          }
        }
        // 动态显示当前时间
        var timestamp = +new Date([that.recordData[TimeRule.current].startTime.split(' ')[0], '00:00:00'].join(' ')) + TimeRule.mul(left + pointWidth / 2, PER * 60 * 1000)
        text = TimeRule.timestampToTime(Math.ceil(timestamp)).split(' ')[1]
        if (that.recordData[0].startTime.split(' ')[0] !== TimeRule.timestampToTime(Math.ceil(timestamp)).split(' ')[0]) {
          text = '24:00:00'
        }
        TimeRule.time.text(text)
      }
    }
  })
  $(document).on('mouseup', function (event) {
    var hasVideo = TimeRule.hasVideo(parseFloat(TimeRule.point.css('left')) + pointWidth / 2)
    event = event || window.event
    event.stopPropagation();
    if(flag) {
      if (hasVideo) {
        if (TimeRule.dragSuccess !== null) TimeRule.dragSuccess(that.recordData[TimeRule.current].startTime.split(' ')[0] + ' ' + text, that.recordData[TimeRule.current].endTime)
      } else {
        if (TimeRule.dragError !== null) TimeRule.dragError()
      }
    }
    flag = false // 阀门关闭，默认无
  })
}

// 拖拽时间轴
TimeRule.dragMark = function (space) {
  var timeRule = TimeRule.timeRule
  var timeRuleWidth = timeRule.width()
  var container = TimeRule.container
  var containerWidth = container.width()
  var containerOffsetLeft = container.offset().left
  var mark = TimeRule.mark
  var prograss = TimeRule.prograss
  var count = 0
  var flag = false //设置一个开关，初始值为false，表示关闭，根据flag限定事件的执行与否
  var x = 0
  var hiddenWidth = 0 // 被隐藏的刻度总宽度
  if (timeRuleWidth > containerWidth) {
    count = 60 * 24 / space
    hiddenWidth = count * 60 - containerWidth
    mark.css('cursor', 'move')
    prograss.css('cursor', 'move')
  } else {
    mark.css('cursor', 'default')
    prograss.css('cursor', 'default')
  }
  timeRule.on('mousedown', function(event) {
    event = event || window.event // 兼容ie
    flag = true//阀门开启
    timeRuleOffsetLeft = $(this).offset().left
    x = event.pageX - timeRuleOffsetLeft // 鼠标与父盒子左侧的水平距离
  })
  timeRule.on('mousemove', function (event) {
    if(flag) {
      event = event || window.event // 兼容ie
      // 设置point水平位置
      $(this).css('left', event.pageX - x - containerOffsetLeft)
      // 超过向右的最大拖动距离
      if ($(this).offset().left >= containerOffsetLeft) {
        $(this).css('left', 0)
      }
      // 超过向左的最大拖动距离
      if (-1 * hiddenWidth >= mark.offset().left - containerOffsetLeft) {
        $(this).css({ left: -1 * hiddenWidth }) // 设置刻度尺水平位置
      }
    }
  })
  $(document).on('mouseup', function (event) {
    flag = false//阀门关闭
  })
}

//渲染刻度尺
TimeRule.renderMark = function (space) {
  var timeRuleMark = ''
  var count = 0
  var num = 0
  var hour = 0
  var minute = 0
  count = 60 * 24 / space // 一共count个li元素
  for (var index = 0; index < count; index++) {
    num += space
    hour = Math.floor(num / 60)
    minute = num % 60
    if (String(hour).length === 1) hour = '0' + hour
    if (String(minute).length === 1) minute = '0' + minute
    timeRuleMark += (
      `
        <li class="time-text"><span>${hour}:${minute}</span></li>
        `
    )
  }
  TimeRule.mark.empty().append(timeRuleMark)
  $('.time-text').outerWidth(TimeRule.container.width() / 24)
  TimeRule.timeRule.width(count * (TimeRule.container.width() / 24))
}
// 渲染时间轴
TimeRule.renderRule = function () {
  var timeRule = ''
  timeRule = (
    `
      <div class="time-rule">
        <div class="time-rule-prograss"></div>
        <ul class="time-rule-mark"></ul>
        <div class="time-rule-point">
          <div class="time">00:00:00</div>
          <class class="point-line"></class>
        </div>
      </div>
      `
  )
  TimeRule.container.empty().append(timeRule).removeClass('time-rule-container').addClass('time-rule-container')
}

// 渲染进度条
TimeRule.renderPrograss = function (themeColor, space, recordData) {
  var prograssItemList = ''
  var PER = space / $('.time-text').outerWidth() // 1个像素对应PER分钟
  // 排序
  recordData.sort(function(a, b) {
    return new Date(a.startTime) - new Date(b.startTime)
  })
  for (var index = 0; index < recordData.length; index++) {
    var prograssItemLength = 0 // 当前视频段的像素长度，保留两位小数
    var prograssItemLeft = 0 // 当前视频段的水平距离，保留两位小数
    prograssItemLength = Math.floor(((((+new Date(recordData[index].endTime) - new Date(recordData[index].startTime)) / 1000) / 60) / PER) * 100) / 100
    prograssItemLeft = Math.floor((((+new Date(recordData[index].startTime) - new Date(recordData[index].startTime.split(' ')[0] + ' 00:00:00')) / 1000) / 60 / PER) * 100) / 100
    if (prograssItemLength < 1) prograssItemLength = 1
    prograssItemList += (`
      <div class="time-rule-prograss-item" style="width: ${prograssItemLength}px;left: ${prograssItemLeft}px" data-startleft="${prograssItemLeft}" data-endleft="${prograssItemLeft + prograssItemLength}"></div>
    `)
  }
  TimeRule.prograss.empty().append(prograssItemList)
  TimeRule.prograssItem = $('.time-rule-prograss .time-rule-prograss-item')
  // 进度条背景色填充
  if (themeColor) {
    TimeRule.prograssItem.css({
      backgroundColor: themeColor
    })
  }
}
// 渲染工具栏
TimeRule.renderToolBar = function (that) {
  var el = that.el
  var space = that.space
  var PER = space / $('.time-text').outerWidth() // 切换间隔前1个像素对应PER分钟
  var themeColor = that.themeColor
  var count = 60 * 24 / space
  var containerWith = 0
  containerWith = TimeRule.container.width()
  timeRuleWidth = TimeRule.timeRule.width()
  TimeRule.container.nextAll().remove()
  TimeRule.container.after(`
    <div class="time-rule-toolbar">
      <div class="time-rule-toolbar-item" data-item="3">3min</div>
      <div class="time-rule-toolbar-item" data-item="30">30min</div>
      <div class="time-rule-toolbar-item" data-item="60">1h</div>
    </div>
  `)
  TimeRule.toolBar = $('.time-rule-toolbar')
  TimeRule.toolBarItem = $('.time-rule-toolbar .time-rule-toolbar-item')
  // 设置高亮效果
  TimeRule.toolBarItem.each(function (i, item) {
    $(item).css('background-color', '#666')
    if ($(item).data('item') === space) {
      $(item).css('background-color', themeColor)
    }
  })
  // 切换时间间隔
  TimeRule.toolBarItem.off().on('click', function() {
    var newSpace = $(this).data('item')
    var newPER = newSpace / $('.time-text').outerWidth() // 当前1个像素对应PER分钟
    var newContainer = $(el)
    var newContainerWidth = newContainer.width() 
    var newTimeRule = TimeRule.timeRule
    var newTimeRuleWidth = newTimeRule.width()
    var point = TimeRule.point
    var pointLeft = point.css('left') // 记录指针位置
    var pointWidth = point.outerWidth()
    var time = TimeRule.time.text() // 记录当前指针上的时间
    var left = (((parseFloat(pointLeft) + pointWidth / 2) * PER) / newPER) - pointWidth / 2 // 当前指针应该在left位置
    // 重新渲染时间轴
    that.init({ el: that.el, space: newSpace, isShowToolBar: that.isShowToolBar, themeColor: that.themeColor, recordData: that.recordData }, TimeRule.beforeInit, TimeRule.afterInit)
    // 重置指针
    TimeRule.point.css({ left: left, transition: 'none' })
    TimeRule.time.text(time)
    // 重置时间轴位置
    newContainerWidth = newContainer.width() // 获取最新容器
    newTimeRule = TimeRule.timeRule // 获取最新时间轴
    newTimeRuleWidth = newTimeRule.width()
    if (left > newContainerWidth) {
      // 指针超出容器范围
      if ((newContainerWidth / 2) > (newTimeRuleWidth - left)) {
        var hiddenWidth = newContainerWidth - newTimeRuleWidth
        // 时间轴最大偏移量
        newTimeRule.css('left', hiddenWidth)
      } else {
        // 指针居中
        newTimeRule.css('left', newContainerWidth - left - (newContainerWidth / 2))
      } 
    }
  })
}
TimeRule.prototype = {
  // 初始化时间轴
  init: function (config, beforeInit, afterInit) {
    this.el = config.el
    this.recordData = config.recordData
    if (config.space) this.space = config.space
    if (config.isShowToolBar) this.isShowToolBar = config.isShowToolBar
    if (config.themeColor) this.themeColor = config.themeColor
    if (beforeInit && typeof beforeInit === 'function') {
      beforeInit(config)
      TimeRule.beforeInit = beforeInit
    }
    if (TimeRule.point) {
      left = TimeRule.point.css('left')
      time = TimeRule.time.text()
    }
    // 保存时间轴容器
    TimeRule.container = $(this.el)
    // 渲染并保存时间轴
    TimeRule.renderRule()
    TimeRule.timeRule = $('.time-rule')
    // 渲染并保存刻度尺
    TimeRule.mark = $('.time-rule-mark')
    TimeRule.renderMark(this.space)
    // 渲染并保存进度条
    TimeRule.prograss = $('.time-rule-prograss')
    TimeRule.renderPrograss(this.themeColor, this.space, this.recordData)
    // 保存指针和指针里的时间
    TimeRule.point = $('.time-rule-point')
    TimeRule.time = $('.time-rule-point .time')
    // 渲染工具栏
    if (config.isShowToolBar) TimeRule.renderToolBar(this)
    // 注册拖拽事件
    TimeRule.dragMark(this.space)
    TimeRule.dragPoint(this)
    // 初始化指针位置
    TimeRule.point.css('left', TimeRule.prograssItem.eq(0).data('startleft') - TimeRule.point.outerWidth() / 2)
    TimeRule.time.text(this.recordData[0].startTime.split(' ')[1])
    if (afterInit && typeof afterInit === 'function') {
      afterInit(config)
      TimeRule.afterInit = afterInit
    }
  },
  // 指针跳转到指定位置
  gotoTime: function(time) {
    var hour = time.hour
    var minute = time.minute
    var second = time.second
    var PER = this.space / $('.time-text').outerWidth() // 1个像素对应PER分钟
    var timeLength = Number(hour) * 60 + Number(minute) + Number(second) / 60 // 一共timeLength分钟
    var pointWidth = TimeRule.point.outerWidth() // point自身的宽度
    var pointLeft = timeLength / PER - (pointWidth / 2) // 指针移动距离
    var text = hour + ':' + minute + ':' + second
    var hasVideo = TimeRule.hasVideo(pointLeft + pointWidth / 2)
    // 校验时间
    // 错误类型：0-正确、1-小时格式错误、2-分钟格式错误、3-秒格式错误、4-当前无视频
    if (!(/^\d{2}$/.test(hour)) || Number(hour) > 24) {
      return {
        isError: true,
        type: 1,
        message: 'time format error'
      }
    }
    if (!(/^\d{2}$/.test(minute)) || Number(minute) > 60) {
      return {
        isError: true,
        type: 2,
        message: 'time format error'
      }
    }
    if (!(/^\d{2}$/.test(second)) || Number(second) > 60) {
      return {
        isError: true,
        type: 3,
        message: 'time format error'
      }
    }
    if (hasVideo) {
      TimeRule.point.css({ 'left': pointLeft, transition: 'left ease 1s' })
      TimeRule.time.text(text)
      // 指针超出可视范围，时间轴位置调整
      if (parseFloat(TimeRule.timeRule.css('left')) + pointLeft < 0 || parseFloat(TimeRule.timeRule.css('left')) + pointLeft > TimeRule.container.width()) {
        if (pointLeft > TimeRule.timeRule.width() - TimeRule.container.width()) {
          TimeRule.timeRule.css('left', (TimeRule.timeRule.width() - TimeRule.container.width()) * -1)
        } else {
          TimeRule.timeRule.css('left', pointLeft * -1 + 10)
        }
      }
      return { isError: false, type: 0, startTime: this.recordData[TimeRule.current].startTime.split(' ')[0] + ' ' + text, endTime: this.recordData[TimeRule.current].endTime }
    } else {
      return {
        isError: true,
        type: 4,
        message: 'no video currently'
      }
    }
  },
  move: function () {
    var PER = this.space / $('.time-text').outerWidth() // 更新PER, 1个像素对应PER分钟
    function move() {
      var point = TimeRule.point
      var pointLeft = parseFloat(point.css('left'))
      var pointWidth = point.outerWidth()
      var prograssList = []
      TimeRule.prograssItem.each(function (i, item) {
        var startLeft = $(item).data('startleft')
        var endLeft = $(item).data('endleft')
        prograssList.push({ startLeft, endLeft })
      })
      // 每隔PER *60秒指针位置+(1 / PER)px
      point.css('left', pointLeft + 1 / PER)
      // 指针移动到最大距离
      if (pointLeft + (pointWidth / 2) > TimeRule.timeRule.width()) {
        this.stop()
        return
      }
      // 当前视频段播放完毕，指针跳转到下一段视频
      if ((pointLeft + (pointWidth / 2)) > prograssList[TimeRule.current].endLeft) {
        // 指针移动到了非最后一个视频的结尾
        if (TimeRule.current + 1 < prograssList.length) {
          TimeRule.current += 1
          point.css('left', prograssList[TimeRule.current].startLeft - (pointWidth / 2))
          TimeRule.time.text(this.recordData[TimeRule.current].startTime.split(' ')[1])
        } else {
          // 指针移动到了最后一个视频结尾
          this.stop()
          return
        }
      }
    }
    this.stop()
    TimeRule.timeId1 = setInterval(move.bind(this), PER * 60 * 1000) // PER * 60 * 1000
    TimeRule.updateTime()
  },
  stop: function () {
    if (TimeRule.timeId1 !== null) clearInterval(TimeRule.timeId1)
    if (TimeRule.timeId2 !== null) clearInterval(TimeRule.timeId2)
  },
  afterDrag: function(dragInfo) {
    TimeRule.dragSuccess = dragInfo.success
    TimeRule.dragError = dragInfo.error
  },
  getPointInfo: function() {
    var startTime = this.recordData[TimeRule.current].startTime
    var currentTime = this.recordData[TimeRule.current].startTime.split(' ')[0] + ' ' + TimeRule.time.text()
    var endTime = this.recordData[TimeRule.current].endTime
    return { startTime: startTime, currentTime: currentTime, endTime: endTime }
  }
}

window.Rule = new TimeRule()
